/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.repository;

import com.inspur.edp.caf.generator.baseInfo.AnnotationInfo;
import com.inspur.edp.caf.generator.baseInfo.AnnotationType;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.cef.api.message.CefException;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.generator.coreGenerator.base.CefCoreGeneratorContext;
import com.inspur.edp.cef.generator.overall.GeneratorUtil;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class RepositoryGenUtil {
  public static <T> T createInstanceByClass(Class<T> type) {
    try {
      return type.newInstance();
    } catch (InstantiationException e) {
      e.printStackTrace();
      throw new RuntimeException("无法创建类型实例：" + type.getSimpleName());
    } catch (IllegalAccessException e) {
      e.printStackTrace();
      throw new RuntimeException("无法创建类型实例：" + type.getSimpleName());
    }
  }

  public static Class getClassByClassName(String typeName) {
    try {
      return Class.forName(typeName);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException("无法获取类型：" + typeName);
    }
  }

  public static Type getTypeByClass(AST ast, Class type) {
    return ast.newSimpleType(ast.newName(type.getTypeName()));
  }

  public static Object createInstanceByClassName(String typeName) {
    try {
      return getClassByClassName(typeName).newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
      throw new RuntimeException("无法创建类型实例：" + typeName);
    }
  }

  /***
   * type varName = XXX；
   * @param ast
   * @param varName
   * @param type
   * @param initializer
   * @return
   */
  public static VariableDeclarationStatement createVariableDeclarationStatement(AST ast, String varName, Type type, Expression initializer) {
    VariableDeclarationFragment declarationFragment = ast.newVariableDeclarationFragment();
    declarationFragment.setName(ast.newSimpleName(varName));
    declarationFragment.setInitializer(initializer);
    VariableDeclarationStatement declaration = ast.newVariableDeclarationStatement(declarationFragment);
    declaration.setType(type);
    return declaration;
  }

  /***
   * expression.methodName(paraList)
   * @param ast
   * @param expression
   * @param methodName
   * @param arguments
   * @return
   */
  public static MethodInvocation createMethodInvocation(AST ast, Expression expression, String methodName, List arguments) {
    MethodInvocation methodInvocation = ast.newMethodInvocation();
    methodInvocation.setName(ast.newSimpleName(methodName));
    if (expression != null)
      methodInvocation.setExpression(expression);
    if (arguments != null && arguments.size() > 0) {
      methodInvocation.arguments().addAll(arguments);
    }
    return methodInvocation;
  }

  /**
   * "Code"
   *
   * @param ast
   * @param propertyName value = Code
   * @return
   */
  public static StringLiteral createStringLiteral(AST ast, String propertyName) {
    StringLiteral stringLiteral = ast.newStringLiteral();
    try{
      stringLiteral.setLiteralValue(propertyName);
    }
    catch (Exception e){
      throw new RuntimeException("字符串"+propertyName+"不合法",e);
    }
    return stringLiteral;
  }


  /**
   * key
   *
   * @param ast
   * @param variableName key
   * @return
   */
  public static Name createVariableLiteral(AST ast, String variableName) {
    return ast.newSimpleName(variableName);
  }

  /**
   * throw new RuntimeException(message);
   *
   * @param ast
   * @param messageExpression
   * @return
   */
  public static ThrowStatement createThrowRuntimeException(AST ast, Expression messageExpression) {
    ThrowStatement throwStatement = GeneratorUtil.getThrowStatement(ast,messageExpression);
//    SetExceptionCode setExceptionCode =new SetExceptionCode();
//    ClassInstanceCreation creation = ast.newClassInstanceCreation();
//    setExceptionCode.setClassInstanceCreation(creation,ast,"","");
//    creation.setType(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(RuntimeException.class).getType(ast));
//    creation.arguments().add(messageExpression);
//    throwStatement.setExpression(creation);
    return throwStatement;
  }

  public static ParameterInfo createParameterInfo(Class type, String paraName) {
    ParameterInfo info = new ParameterInfo();
    info.setParamType(new TypeInfo(type.getTypeName()));
    info.setParamName(paraName);
    return info;
  }

  public static TypeInfo getHashMapTypeInfo(AST ast, Class keyClass, Class valueClass) {
    ParameterizedType hashMapType = ast.newParameterizedType(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(HashMap.class).getType(ast));
    Type keyType = getTypeByClass(ast, keyClass);
    Type valueType = getTypeByClass(ast, valueClass);
    hashMapType.typeArguments().add(keyType);
    hashMapType.typeArguments().add(valueType);
    return new TypeInfo(hashMapType.getClass().getTypeName());
  }

  public static ArrayList<Modifier.ModifierKeyword> createModifierKeywordArray(Modifier.ModifierKeyword keyword) {
    ArrayList<Modifier.ModifierKeyword> list = new ArrayList<>();
    list.add(keyword);
    return list;
  }

  public static Block buildReturnOneSimpleVariableName(AST ast, String returnValue) {
    Block block = ast.newBlock();
    ReturnStatement returnStatement = ast.newReturnStatement();
    returnStatement.setExpression(RepositoryGenUtil.createVariableLiteral(ast, returnValue));
    block.statements().add(returnStatement);
    return block;
  }

  public static Block buildReturnOneSimpleString(AST ast, String returnValue) {
    Block block = ast.newBlock();
    ReturnStatement returnStatement = ast.newReturnStatement();
    returnStatement.setExpression(RepositoryGenUtil.createStringLiteral(ast, returnValue));
    block.statements().add(returnStatement);
    return block;
  }

  public static ArrayList<AnnotationInfo> buildOverrideAnnotationInfo(AST ast) {
    ArrayList<AnnotationInfo> list = new ArrayList<>();
    AnnotationInfo info = new AnnotationInfo();
    info.setAnnotationType(AnnotationType.Marker);
    info.setTypeInfo(new TypeInfo(Override.class));
    list.add(info);
    return list;
  }

  public static Expression getStringArgument(AST ast, String string) {
    return createStringLiteral(ast, string);
  }

  public static Expression getBoolArgumnet(AST ast, boolean value) {
    return ast.newBooleanLiteral(value);
  }

  public static Expression getNumberArgument(AST ast, String value) {
    return ast.newNumberLiteral(value);
  }

  public static Expression getNullArgument(AST ast) {
    return ast.newNullLiteral();
  }

  public static <T> T getBeanByType(Class<T> type) {
    return SpringBeanUtils.getBean(type);
//        return BeanUtil.getAppCtx().getBean(type);
  }

  public static String getConfigID(CefCoreGeneratorContext cefCoreGeneratorContext){
    String configId = "";
    IGspCommonDataType commonDataType = cefCoreGeneratorContext.getCefGenContext().getCommonDataType();
    configId = commonDataType.getCode();
//    if(commonDataType instanceof GspBizEntityObject){
//      configId = ((GspBizEntityObject)commonDataType).getCode();
//    }
//    else if(commonDataType instanceof SimpleDataTypeDef){
//      configId = ((SimpleDataTypeDef)commonDataType).getCode();
//    }
    return configId;
  }
}
